package com.xsy.middleware.utils;

import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

/**
 * 功能描述：获取销售易信息工具类
 *
 * @author whz
 * @ClassName: CrmApiUtils
 * @Description:
 * @date 2024年04月12日
 */
@Component
public class CrmApiUtils {
    private final static Logger logger = LoggerFactory.getLogger(CrmApiUtils.class);

    @Value("${xsy.userName}")
    private String username;
    @Value("${xsy.password}")
    private String password;
    @Value("${xsy.securityCode}")
    private String securityCode;
    @Value("${xsy.clientId}")
    private String clientId;
    @Value("${xsy.clientSecret}")
    private String clientSecret;
    @Value("${xsy.domain}")
    private String domain;
    private static String LOGIN_URL = "https://login.xiaoshouyi.com/auc/oauth2/token"; // 获取销售易token接口
    private static String QUERY_API_URI = "/rest/data/v2/query"; // 查询接口
    private static String API_V20_URL = "/rest/data/v2.0/xobjects";
    private static String XOQL_QUERY = "/rest/data/v2.0/query/xoql"; // xoql查询接口
    private Cache cacheApi;

    @PostConstruct
    public void init() {
        // 获取缓存对象
        ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
        cacheApi = cacheManager.getCache("default");
    }

    public JSONArray getTableData(String xoql) {
        JSONArray arrays = new JSONArray();
        getAllDatasForXoql(xoql, arrays, 0);
        logger.info("总数量：" + arrays.size());
        return arrays;
    }

    private void getAllDatasForXoql(String xoql, JSONArray arrays, int num) {
        StringBuilder sqlBulder = new StringBuilder(xoql);
        sqlBulder.append(" order by id desc ");
        sqlBulder.append(" LIMIT ");
        sqlBulder.append(3000);
        sqlBulder.append(" OFFSET ");
        sqlBulder.append(num);
        HttpResponse execute = HttpUtil.createPost(domain + XOQL_QUERY)
                .form("xoql", sqlBulder.toString())
                .form("useSimpleCode", true)
                .header("Authorization", "Bearer " + getToken())
                .execute();
        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                getAllDatasForXoql(xoql, arrays, num);
            } else {
                // 不抛异常
                System.out.println("getAllDatasForXoql 查询数据失败 = " + msg);
                throw new RuntimeException("查询数据失败：" + msg);
            }
        }
        JSONObject data = result.getJSONObject("data");
        Integer count = data.getInteger("count");
        arrays.addAll(data.getJSONArray("records"));
        if (count < 3000) {
            return;
        }
        getAllDatasForXoql(xoql, arrays, num + 3000);
    }

    public Long getTotalSize(String xoql) {
        HttpResponse execute = HttpUtil.createPost(domain + XOQL_QUERY).form("xoql", xoql)
                .header("Authorization", "Bearer " + getToken())
                .execute();
        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return getTotalSize(xoql);
            }
            throw new RuntimeException("查询数据失败：" + msg);
        }
        Long count = result.getJSONObject("data").getLong("totalSize");
        logger.info("数据总量：" + count);
        return count;
    }

    public JSONObject queryOne(String sql) throws UnsupportedEncodingException {
        sql = sql + " limit 0,1";
        HttpResponse execute = HttpUtil.createGet(domain + QUERY_API_URI + "?q=" + URLEncoder.encode(sql, "UTF-8"))
                .header("xsy-criteria", "10")
                .header("Authorization", "Bearer " + getToken())
                .execute();
        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return queryOne(sql);
            }
            throw new RuntimeException("查询数据失败：" + msg);
        }
        JSONArray jsonArray = result.getJSONObject("result").getJSONArray("records");
        if (jsonArray.size() <= 0) {
            return null;
        }
        JSONObject object = jsonArray.getJSONObject(0);
        return object;
    }

    public JSONArray query(String sql) throws UnsupportedEncodingException {
        sql = sql + " limit 0,300";
        HttpResponse execute = HttpUtil.createGet(domain + QUERY_API_URI + "?q=" + URLEncoder.encode(sql, "UTF-8"))
                .header("xsy-criteria", "10")
                .header("Authorization", "Bearer " + getToken())
                .execute();
        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return query(sql);
            }
            throw new RuntimeException("查询数据失败：" + msg);
        }
        JSONArray jsonArray = result.getJSONObject("result").getJSONArray("records");
        return jsonArray;
    }

    /**
     * 修改数据
     * @param apikey
     * @param jsonObject
     * @return
     * @throws UnsupportedEncodingException
     */
    public ResultVo update(String apikey, JSONObject jsonObject) throws UnsupportedEncodingException {
        StringBuilder sb = new StringBuilder();
        sb.append("{\"data\":").append(JSON.toJSONString(jsonObject)).append("}");

        String requestUrl = domain + API_V20_URL + "/" + apikey + "/" + jsonObject.get("id");
        HttpResponse execute = HttpUtil.createRequest(Method.PATCH, requestUrl)
                .header("xsy-criteria", "10")
                .header("Authorization", "Bearer " + getToken())
                .body(sb.toString())
                .execute();

        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return update(apikey, jsonObject);
            }
            return ResultVo.error("修改数据失败" + msg);
        }
        return ResultVo.success();
    }

    /**
     * 新增数据
     * @param apikey
     * @param jsonObject
     * @return
     * @throws UnsupportedEncodingException
     */
    public ResultVo insert(String apikey, JSONObject jsonObject) throws UnsupportedEncodingException {
        StringBuilder sb = new StringBuilder();
        sb.append("{\"data\":").append(JSON.toJSONString(jsonObject)).append("}");

        String requestUrl = domain + API_V20_URL + "/" + apikey;
        HttpResponse execute = HttpUtil.createPost(requestUrl)
                .header("xsy-criteria", "10")
                .header("Authorization", "Bearer " + getToken())
                .body(sb.toString())
                .execute();

        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return insert(apikey, jsonObject);
            }
            return ResultVo.error("新增数据失败: " + msg);
        }
        // 获取返回的主键id
        JSONObject resultData = result.getJSONObject("data");
        return ResultVo.success(resultData.get("id"));
    }

    /**
     * 批量新增数据
     * @param apikey
     * @param jsonArray
     * @return
     * @throws UnsupportedEncodingException
     */
    public ResultVo batchInsert(String apikey, JSONArray jsonArray) throws UnsupportedEncodingException {

        // 处理批量新增的数据
        JSONArray bodyData = new JSONArray();
        for (Object obj : jsonArray) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("data", obj);
            bodyData.add(jsonObject);
        }

        StringBuilder sb = new StringBuilder();
        sb.append("{\"batchData\":").append(JSON.toJSONString(bodyData)).append("}");

        String requestUrl = domain + API_V20_URL + "/" + apikey + "/batch";
        HttpResponse execute = HttpUtil.createPost(requestUrl)
                .header("xsy-criteria", "10")
                .header("Authorization", "Bearer " + getToken())
                .body(sb.toString())
                .execute();

        JSONObject result = JSONObject.parseObject(execute.body());
        System.out.println("result = " + result);
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return batchInsert(apikey, jsonArray);
            }
            return ResultVo.error("批量新增数据失败: " + msg);
        }
        return ResultVo.success();
    }

    /**
     * 删除数据
     * @param apikey
     * @param dataId
     * @return
     * @throws UnsupportedEncodingException
     */
    public ResultVo delete(String apikey, Long dataId) {
        String requestUrl = domain + API_V20_URL + "/" + apikey + "/" + dataId;
        HttpResponse execute = HttpUtil.createRequest(Method.DELETE, requestUrl)
                .header("xsy-criteria", "10")
                .header("Authorization", "Bearer " + getToken())
                .execute();
        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return delete(apikey, dataId);
            }
            return ResultVo.error("删除数据失败: " + msg);
        }
        return ResultVo.success("删除数据成功");
    }


    /**
     * 获取表描述
     * @param tableName
     * @return
     */
    public JSONObject queryEntityDesc(String tableName) {
        String requestUrl = domain + API_V20_URL + "/" + tableName + "/description";
        HttpResponse execute = HttpUtil.createGet(requestUrl)
                .header("Authorization", "Bearer " + getToken())
                .execute();

        JSONObject result = JSONObject.parseObject(execute.body());
        Integer code = result.getInteger("code");
        String msg = result.getString("msg");
        if (code != 200) {
            // 处理 token 过期
            if (msg.equals("无效的access token") || code == 1020008) {
                System.out.println("重新获取 token ");
                cacheApi.put("tokenInfo", null);
                return queryEntityDesc(tableName);
            }
            throw new RuntimeException("code:" + code + " === > 查询数据失败：" + msg);
        }

        JSONObject jsonObject = result.getJSONObject("data");
        return jsonObject;
    }

    // 模拟token过期
    public void setToken() {
        JSONObject jsonObject = cacheApi.get("tokenInfo", JSONObject.class);
        String accessToken = jsonObject.getString("access_token");
        accessToken += "1";
        jsonObject.put("access_token", accessToken);
        cacheApi.put("tokenInfo", jsonObject);
        System.out.println("jsonObject = " + jsonObject);
    }

    // 清空token
    public String clearToken() {
        cacheApi.put("tokenInfo", null);
        return "清空token成功";
    }

    public String getToken() {
        JSONObject tokenInfo = cacheApi.get("tokenInfo", JSONObject.class);
        if (tokenInfo != null) {
            String token = tokenInfo.getString("access_token");
            return token;
        }
        logger.info("没有缓存token，开始查询销售易token  =======> ");
        String url = "%s?grant_type=password&client_id=%s&client_secret=%s&username=%s&password=%s%s";
        url = String.format(url, LOGIN_URL, clientId, clientSecret, username, password, securityCode);

        HttpResponse execute = HttpUtil.createGet(url).execute();
        tokenInfo = JSONObject.parseObject(execute.body());
        logger.info("token信息：" + tokenInfo);
        cacheApi.put("tokenInfo", tokenInfo);
        String token = tokenInfo.getString("access_token");
        return token;
    }
}
